package com.chatplus.application.web.idempotent.generator;

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 简单的 spring el 值 生成实现
 *
 * @author chenxiaobo
 */
public class SpelExpressionValueGenerator implements ValueGenerator {
    /**
     * 默认的 key 前缀
     */
    private static final String DEFAULT_PREFIX = "spring:el:value:generator:";

    /**
     * key 前缀
     */
    @Setter
    @Getter
    private String prefix = DEFAULT_PREFIX;

    /**
     * 变量截取的开始字符
     */
    @Setter
    @Getter
    private String openCharacter = "[";

    /**
     * 变量截取的结束字符
     */
    @Setter
    @Getter
    private String closeCharacter = "]";

    /**
     * spring el 表达式解析器
     */
    private final SpelExpressionParser parser = new SpelExpressionParser();

    /**
     * 参数名称发现者，用于获取方法参数明细信息
     */
    private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();


    @Override
    public Object generate(String expression, Method method, Object... args) {

        String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);

        Map<String, Object> variables = new LinkedHashMap<>();

        if (ArrayUtils.isNotEmpty(args)) {
            for (int i = 0; i < (parameterNames != null ? parameterNames.length : 0); i++) {
                variables.put(parameterNames[i], args[i]);
            }
        }

        List<String> tokens = new LinkedList<>();

        String[] array = StringUtils.substringsBetween(expression, openCharacter, closeCharacter);
        if (ArrayUtils.isNotEmpty(array)) {
            tokens = Arrays.asList(array);
        }

        StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
        evaluationContext.setVariables(variables);

        String result = expression;

        List<String> replaceToken = new LinkedList<>();

        for (String t : tokens) {

            if (replaceToken.contains(t)) {
                continue;
            }

            Object value = parser.parseExpression(t).getValue(evaluationContext, String.class);

            if (Objects.nonNull(value)) {
                result = StringUtils.replace(result, getTokenValue(t), value.toString());
            }

            replaceToken.add(t);
        }

        return Objects.toString(getPrefix(), StringUtils.EMPTY) + result;
    }


    /**
     * 获取 token 值
     *
     * @param token token 值
     * @return 添加开始和结束字符的 token 内容,如
     */
    private String getTokenValue(String token) {
        return openCharacter + token + closeCharacter;
    }

}
